﻿#pragma once
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <string> 
#include <CommCtrl.h>
#include <unordered_map>
#include <functional>
#include <shellapi.h>
#include <iostream>

#include <objidl.h>

#include <uxtheme.h>
#include "zyBuffGraphics.h"

#include "zyUIStruct.h"//引入的自定义宏/枚举/数据类型

#define ZY_DISABLE_COPY(Class) Class(const Class &) = delete; Class &operator=(const Class &) = delete;
#define ZY_DISABLE_MOVE(Class) Class(Class &&) = delete; Class &operator=(Class &&) = delete;
#define ZY_DISABLE_COPY_MOVE(Class) ZY_DISABLE_COPY(Class) ZY_DISABLE_MOVE(Class)

//#define BLACKMOON_EXPORTS
//// 檢查是否定義了 BLACKMOON_STATIC_LIB。如果定義了，代表我們要編譯或使用「靜態庫」。
//#ifdef BLACKMOON_STATIC_LIB
//#define BLACKMOON_API
//
//// 如果沒有定義 BLACKMOON_STATIC_LIB，代表我們要處理「動態庫 (DLL)」。
//#else
//    // 檢查是否定義了 BLACKMOON_EXPORTS。這是我們在「建置 DLL 本身」時才定義的。
//#ifdef BLACKMOON_EXPORTS
//#define BLACKMOON_API __declspec(dllexport) // 導出
//#else
//#define BLACKMOON_API __declspec(dllimport) // 導入
//#endif
//#endif

//@模块名称  黑月界面类模块
//@版本  1.0
//@日期  2024-08-07
//@作者  易团雪,感谢:逸辰Arne,飞等大佬的技术支持  
//@模块备注 本模块翻译与整理自易语言黑月界面类,

//@命名空间      BlackMoonUI
//@命名空间别名  黑月UI
//@隐藏{
namespace BlackMoonUI {
//@隐藏}
    // 前向申明
    class zyObject;
    class zyWindow;

    typedef LRESULT(WINAPI* FnWndProc)(zyObject*, HWND, UINT, WPARAM, LPARAM, BOOL*);
    typedef LRESULT(WINAPI* FnChildWndProc)(zyObject*, HWND, UINT, WPARAM, LPARAM, BOOL*);
    typedef void(WINAPI* FnDestroy)(zyObject*);



    zyObject* 子程序_取资源控件(HWND 参数_父窗口句柄, const std::wstring& 参数_控件名);
    zyObject* 黑月取资源控件(HWND 参数_父窗口句柄, const std::wstring& 参数_控件名);
    HWND 黑月取根窗口(HWND hWndParam);
    RECT 黑月到屏幕矩形(HWND 参数_窗口句柄, RECT& 参数_矩形);
    RECT 黑月到窗口矩形(HWND 参数_窗口句柄, RECT& 参数_屏幕矩形);
    int 黑月默认ID();
    //将字符串转换为矩形结构
    RECT zyStringToRECT(const wchar_t* wstr);
    //从文件路径字符串中移除文件名部分,仅保留目录路径
    bool zyPathRemoveFileSpec(wchar_t* path);
    //将当前工作目录设置为进程所在目录,此函数的目的是确保进程在其自身的目录中执行,这在某些情况下对于资源定位和管理非常重要
    void zySetCurrentDirectoryToProcessDirectory();
    /**
     * 将二进制文件的内容保存到一个C/C++头文件中
     *
     * 此函数的目的是将指定的二进制文件转换为一个C/C++头文件该头文件将包含
     * 一个数组，数组中包含了二进制文件的所有字节这样做的目的是为了在C/C++
     * 项目中方便地包含二进制数据，而不需要在源代码中直接写入大量的二进制数据
     *
     * @param data  输入参数，指定要转换的二进制数据
     * @param outputFilePath 输出参数，指定要生成的C/C++头文件的路径
     * @param variableName   输出参数，指定在生成的头文件中使用的变量名
     * @return 返回一个整数，表示函数执行的结果状态
     */   
    void zySaveBinaryToHeaderFile(const std::vector<unsigned char>& data,const char* outputFilename, const char* arrayName);
    //将指定文件以二进制形式读取到内存中，跨平台兼容性
    std::vector<BYTE> zyReadFileToBinary(const std::wstring& filePath);
    //读取文件内容
    BOOL zyReadFile(LPCWSTR filePath, std::vector<CHAR>* retData);
    //用于提前处理或过滤窗口消息
    BOOL preTranslateMessage(HWND hWnd, zyObject* this_, MSG& msg);
    static LRESULT WINAPI WndProc_(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
    ATOM MyRegisterClass(HINSTANCE hInstance, const std::wstring& 参数_类名, WNDPROC 参数_窗口过程, HICON 参数_图标句柄, int 参数_类风格 = -1);

    // 环境App类
    class zyApplications {
    public:
        static zyApplications& getInstance() {
            static zyApplications instance;
            return instance;
        }

        //private 构造函数不能私有
        zyApplications();// : m_hInst(GetModuleHandle(NULL)), m_bEnableDpiConvert(FALSE) {}
        ~zyApplications();

        zyApplications(const zyApplications&) = delete;
        zyApplications& operator=(const zyApplications&) = delete;

        void 初始化(HINSTANCE hInstance = NULL, BOOL 参数_使用ATL = FALSE, UINT 参数_通用控件类 = 0);
      
        int 运行(zyWindow& bform, BOOL Bshow = TRUE);

        int AtlAxWinInit_();
        std::wstring GetDirectory() const;
        int 取命令行(std::vector<std::wstring>& 参数_命令行参数);
        std::wstring GetFileName() const;
        std::wstring GetRoute() const;
        void 结束();
        //获取DPI
        int getDpiForWindow();
        //DPI转换
        void dpiConvert(POINT& pt);
        //启用DPI转换
        void enableDpiConvert(BOOL bEnable);
        //注册窗口
        void registerWnd(HWND hWnd, zyObject* pObject);
        //移除窗口
        void unregisterWnd(HWND hWnd);
        //获取窗口对象
        zyObject* getWndObject(HWND hWnd);
        //获取模块句柄
        HINSTANCE getHandle() const;
        //设置模块句柄
        void setHandle(HINSTANCE hInst);

    private:
        HINSTANCE m_hInst;
        BOOL m_bEnableDpiConvert;
        std::unordered_map<HWND, zyObject*> m_wndEventMap;
        ULONG_PTR m_pGdiToken = 0;
    };

    using zyEnv = zyApplications;

    // 抽象基类
    class MemberFunctionCallerBase {
    public:
        virtual ~MemberFunctionCallerBase() = default;
        virtual void Call() = 0;
    };

    // 回调注册类
    template <typename R, typename... Args>
    class MemberFunctionCaller : public MemberFunctionCallerBase {
    private:
        std::function<R(Args...)> func; // 使用 std::function 存储可调用对象

    public:
        // 绑定成员函数
        template <typename C>
        MemberFunctionCaller(C* object, R(C::* memberFunc)(Args...)) {
            func = [object, memberFunc](Args... args) -> R {
                return (object->*memberFunc)(args...);
                };
        }

        // 绑定自由函数
        MemberFunctionCaller(R(*freeFunc)(Args...)) {
            func = [freeFunc](Args... args) -> R { return freeFunc(args...); };
        }

        // 调用函数
        R Call(Args... arguments) {
            return func(arguments...);
        }

        // 实现基类的纯虚函数
        void Call() override {}
    };

    // 回调触发类
    class TRegEvent {
    public:
        std::unique_ptr<MemberFunctionCallerBase> m_pBind; // 使用智能指针管理资源

        TRegEvent() = delete;

        explicit TRegEvent(MemberFunctionCallerBase* pBind) : m_pBind(pBind) {}

        ~TRegEvent() = default; // 不需要手动释放资源

        // 调用回调函数
        template <typename T, typename... Args>
        T handler(Args... args) {
            auto* caller = static_cast<MemberFunctionCaller<T, Args...>*>(m_pBind.get());
            if (caller) {
                return caller->Call(args...);
            }
            throw std::runtime_error("Invalid callback type");
        }
    };

    // 注册成员函数回调
    template <typename R, typename C, typename... Args>
    TRegEvent* TRegEventCallBack(C* c, R(C::* func)(Args...)) {
        return new TRegEvent(new MemberFunctionCaller<R, Args...>(c, func));
    }

    // 注册自由函数回调
    template <typename R, typename... Args>
    TRegEvent* TRegEventCallBack(R(*func)(Args...)) {
        return new TRegEvent(new MemberFunctionCaller<R, Args...>(func));
    }

    //@备注 注册C函数使用
    //函数支持任意类型
    //@别名 注册事件C_取地址(事件函数)
    #define TRegEventC_Ptr(mFun)  TRegEventCallBack(mFun)
    //@备注 注册类回调使用,取得事件类地址,需要使用类名一起，如:&类名::函数名
    //函数支持任意类型
    //@别名 注册事件CPP_取地址(事件函数)
    #define TRegEventCPP_Ptr(mFun)  TRegEventCallBack(this,mFun)



}
